#include "RestoreInterface.h"

int restore_mount(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" || args[2] == "")
    {
      ifNotQuiet cout << "mount: please provide both arguments." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Mount"));
  CFDictionarySetValue(req, CFSTR("DeviceName"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII));
  CFDictionarySetValue(req, CFSTR("MountPoint"),
                       CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII));
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "mount: mounting '" << args[1] << "' at '" << args[2] << endl;
        
  // build a list of known error codes
  ifNotQuiet
    {
      switch (retval)
        {
        case 0:
          ifVerbose cout << "mount: Successful." << endl;
          break;
        case 6:
          cout << "mount: iPhone returned '6' - invalid argument." << endl;
          break;
        default:
          cout << "mount: iPhone returned '" << retval << "' - unknown error code." << endl;
          break;
        }
    }
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
        
  return SHELL_CONTINUE;
}

int restore_partition(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Partition"));
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "partition: returned error code: "
                  << retval << endl;
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
        
  return SHELL_CONTINUE;
}

int restore_erase(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" || args[2] == "")
    {
      ifNotQuiet cout << "mount: please provide both arguments." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Erase"));
  CFDictionarySetValue(req, CFSTR("DeviceName"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
  CFDictionarySetValue(req, CFSTR("VolumeName"),
                       CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII) );
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "erase: erasing device '" << args[1] << "' at volume '" << args[2] << "': " << retval << endl;
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
                
  return SHELL_CONTINUE;
}

int restore_ditto(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" || args[2] == "")
    {
      ifNotQuiet cout << "ditto: please provide both arguments." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Ditto"));
  CFDictionarySetValue(req, CFSTR("SourcePath"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
  CFDictionarySetValue(req, CFSTR("DestinationPath"),
                       CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII) );
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "ditto: copying file '" << args[1] << "' to '" << args[2] << "': " << retval << endl;
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
        
  return SHELL_CONTINUE;
}

int restore_umount(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" )
    {
      ifNotQuiet cout << "umount: please provide an argument." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Unmount"));
  CFDictionarySetValue(req, CFSTR("MountPoint"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "umount: Unmounting '" << args[1] << "': " << retval << endl;
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
        
  return SHELL_CONTINUE;
}

int restore_filesystemcheck(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" )
    {
      ifNotQuiet cout << "filesystemcheck: please provide a path to a disk to check." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("FilesystemCheck"));
  CFDictionarySetValue(req, CFSTR("DeviceName"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "FileSystemCheck: checking device '" << args[1] << "': " << retval << endl;
        
  //Here we should check for 'unknown device' error code to assume that anything else means
  //that fsck could not repair the disk, which we should alert the user to.
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
        
  return SHELL_CONTINUE;
}

int restore_mkdir(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" || args[2] == "")
    {
      ifNotQuiet cout << "mkdir: please provide both arguments." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
        
  D("setting values");                                                    
  CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("MakeDirectory"));
  CFDictionarySetValue(req, CFSTR("Mode"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
  CFDictionarySetValue(req, CFSTR("Path"),
                       CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII) );
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);
        
  ifVerbose cout  << "mkdir: creating directory with modes '"
                  << args[1] << "' at location '" << args[2] <<  "': " << retval << endl;
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
                        
  return SHELL_CONTINUE;
}

int restore_force(string *args, struct shell_state *sh)
{
  mach_error_t retval;
        
  if( args[1] == "" )
    {
      ifNotQuiet cout << "force: please provide a command." << endl;
      set_rfr(1);
      return SHELL_CONTINUE;
    }
        
  D("allocating CFMutableDictionary");
  CFMutableDictionaryRef req = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                                          &kCFTypeDictionaryKeyCallBacks,
                                                          &kCFTypeDictionaryValueCallBacks);
                                                        
  D("setting values");
  CFDictionarySetValue(req, CFSTR("Operation"),
                       CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
        
  D("sending dictionary");
  retval = performOperation(sh->restore_dev, req);

  ifVerbose cout  << "force: sending operation: '" << args[1] << "'" << endl;
        
  ifNotQuiet
    {
      switch(retval)
        {
        case 0:
          ifVerbose cout << "force: Successful." << endl;
          break;
        case 8:
          cout << "force: Unknown command." << endl;
          break;
        default:
          cout << "force: Unknown error code '" << retval << "'.  Please report." << endl;
          break;
        }
    }
        
  // set return function retval so we can break a script if this doesn't work for some reason
  set_rfr(retval);
        
  return SHELL_CONTINUE;
}

int restore_exit(string *args, struct shell_state *sh)
{
  ifNotQuiet cout << "shell: exiting restore mode." << endl;
  ifVerbose cout << "shell: If connected, the phone may restart itself. Otherwise use button combo." << endl;
  set_rfr(0);
  return SHELL_WAIT;
}
